﻿using HybridCLR;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEngine;

class Loader
{
    private static readonly string[] HOT_DLL = new string[]
    {
        "mscorlib",
        "Main",
        "UnityEngine.CoreModule",
    };
    private static readonly string[] HOT_UPDATE_DLL = new string[]
    {
        "HotUpdate"
    };

    public static async Task LoadHybridCLR()
    {
        foreach (var name in HOT_DLL)
        {
            await LoadAotAssembly(name);
        }

        foreach (var name in HOT_UPDATE_DLL)
        {
            if (null == await LoadAssembly(name))
            {
                throw new Exception($"load Assembly fail! {name}");
            }
        }

        Debug.Log("Load HybridCLR Finish");
    }

    static async Task LoadAotAssembly(string name)
    {
#if !ENABLE_HYBRID_CLR
        return;
#endif
        if (ResourceHelper.IsAsync)
        {
            var contnet = await ResourceHelper.ReadAsync($"Code/Aot/{name}.bytes");
            if (contnet != null)
            {
                var code = RuntimeApi.LoadMetadataForAOTAssembly(contnet, HomologousImageMode.SuperSet);
                if (code != LoadImageErrorCode.OK)
                {
                    Debug.LogError($"LoadMetadataForAOTAssembly error:{name} code:{code}");
                }
                else
                {
                    Debug.Log($"Load aot {name}.dll succeed");
                }
            }
        }
    }
    static async Task<Assembly> LoadAssembly(string name)
    {
        if (ResourceHelper.IsAsync)
        {
#if ENABLE_HYBRID_CLR
            var contnet = await ResourceHelper.ReadAsync($"Code/Runtime/{name}.bytes");
            if (contnet != null)
            {
                try
                {
                    var assembly = Assembly.Load(contnet);
                    Debug.Log($"Load hot update {name}.dll succeed");
                    return assembly;
                }
                catch (Exception ex)
                {
                    Debug.LogError($"Load {name}.dll fail!\n{ex.Message}");
                }
            }
            Debug.LogError($"Load {name}.dll fail!");
            return default;
#else
            return GetAssembly(name);
#endif
        }
        else
        {
            return GetAssembly(name);
        }
    }

    public static Assembly GetAssembly(string name)
    {
        return AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == name);
    }
}
